﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using AForge.Video.DirectShow;
using AForge.Video;

namespace SimpleGUI.DetectionMethods.Simple2Cameras
{

	public partial class ControlPanel : Form
	{
		#region private properties

		#region stats
		/// <summary>
		/// statistics length
		/// </summary>
		private const int statLength = 15;

		/// <summary>
		/// current statistics index
		/// </summary>
		private int statIndex = 0;

		/// <summary>
		/// ready statistics values
		/// </summary>
		private int statReady = 0;

		/// <summary>
		/// statistics array 1
		/// </summary>
		private int[] statCount1 = new int[statLength];

		/// <summary>
		/// statistics array 2
		/// </summary>
		private int[] statCount2 = new int[statLength];

		#endregion


		#endregion

		/// <summary>
		/// Dart detected event!
		/// </summary>
		public event DartDetectionEventHandler DartDetected;

		/// <summary>
		/// List with video devices
		/// </summary>
		private FilterInfoCollection videoDevices;

		/// <summary>
		/// Frame processor, graps dart coords in 2D space from a frame.
		/// For video source 1
		/// </summary>
		private FrameProcessor frameProcessor1;

		/// <summary>
		/// Frame processor, graps dart coords in 2D space from a frame.
		/// For video source 1
		/// </summary>
		private FrameProcessor frameProcessor2;

		/// <summary>
		/// Constructor;
		/// - setup device list 
		/// - initiate FrameProcessor
		/// </summary>
		public ControlPanel()
		{
			InitializeComponent();

			#region show device list
			// enumerate video devices
			videoDevices = new FilterInfoCollection(FilterCategory.VideoInputDevice);

			// no cameras? -> go to catch!
			if (videoDevices.Count == 0)
			{
				cmbCamera1.Enabled = false;
				cmbCamera2.Enabled = false;

				cmbCamera1.Items.Add("No cameras found");
				cmbCamera2.Items.Add("No cameras found");

				cmbCamera1.SelectedIndex = 0;
				cmbCamera2.SelectedIndex = 0;
			}
			else
			{

				// loop through cameras
				for (int i = 1, n = videoDevices.Count; i <= n; i++)
				{
					string cameraName = i + " : " + videoDevices[i - 1].Name;
					cmbCamera1.Items.Add(cameraName);
					cmbCamera2.Items.Add(cameraName);
				}

				// Only 1 camera? Disable second!
				if (videoDevices.Count == 1)
				{
					cmbCamera2.Items.Clear();
					cmbCamera2.Items.Add("Only one camera found");
					cmbCamera2.Enabled = false;
					cmbCamera2.SelectedIndex = 0;
				}
				else
				{
					cmbCamera2.SelectedIndex = 1;
				}
				cmbCamera1.SelectedIndex = 0;
			}
			#endregion

			// start frame processor
			frameProcessor1 = new FrameProcessor(1);
			frameProcessor1.CoordDetected += new DartCoordEventHandler(frameProcessor_CoordDetected);
			
			frameProcessor2 = new FrameProcessor(2);
			frameProcessor2.CoordDetected += new DartCoordEventHandler(frameProcessor_CoordDetected);
		}

		

		/// <summary>
		/// There is a coord detected, try making a dartScore out of it.
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="coord"></param>
		void frameProcessor_CoordDetected(object sender, int coord)
		{
			// dartScore was found, pass it through
			if (this.DartDetected != null)
				this.DartDetected(this, coord);
		}

		/// <summary>
		/// Hide the form
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void btnClose_Click(object sender, EventArgs e)
		{
			this.Hide();
		}

		/// <summary>
		/// Form may not be closed, Dispose it, to kill it.
		/// Closing it, will hide it...
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void Setup_FormClosing(object sender, FormClosingEventArgs e)
		{
			this.Hide();
			e.Cancel = true;
		}

		/// <summary>
		/// Timer ticked, update fps stats
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void timer_Tick(object sender, EventArgs e)
		{
			IVideoSource videoSource1 = videoSourcePlayer1.VideoSource;
			IVideoSource videoSource2 = videoSourcePlayer2.VideoSource;

			// get number of frames for the last second
			if (videoSource1 != null)
				statCount1[statIndex] = videoSource1.FramesReceived;
			if (videoSource2 != null)
				statCount2[statIndex] = videoSource2.FramesReceived;

			// increment indexes
			if (++statIndex >= statLength)
				statIndex = 0;
			if (statReady < statLength)
				statReady++;

			float fps1 = 0;
			float fps2 = 0;

			// calculate average value
			for (int i = 0; i < statReady; i++)
			{
				fps1 += statCount1[i];
				fps2 += statCount2[i];
			}
			fps1 /= statReady;
			fps2 /= statReady;

			statCount1[statIndex] = 0;
			statCount2[statIndex] = 0;

			camera1GroupBox.Text = string.Format("Camera 1 ({0} fps)", fps1);
			camera2GroupBox.Text = string.Format("Camera 2 ({0} fps)", fps2);
		}

		/// <summary>
		/// Select camera 1
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void cmbCamera1_SelectedIndexChanged(object sender, EventArgs e)
		{
			if (cmbCamera1.Enabled == true)
			{
				// stop previous video source
				timer.Stop();
				StopCamera1();

				// create first video source
				VideoCaptureDevice videoSource1 = new VideoCaptureDevice(videoDevices[cmbCamera1.SelectedIndex].MonikerString);
				videoSource1.DesiredFrameRate = 20;
				videoSource1.DesiredFrameSize = new Size(640, 480);
				videoSourcePlayer1.VideoSource = videoSource1;
				videoSourcePlayer1.Start();

				// start timer
				timer.Start();
			}
		}

		/// <summary>
		/// Select camera 2 
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void cmbCamera2_SelectedIndexChanged(object sender, EventArgs e)
		{
			if (cmbCamera2.Enabled == true)
			{
				timer.Stop();
				StopCamera2();

				VideoCaptureDevice videoSource2 = new VideoCaptureDevice(videoDevices[cmbCamera2.SelectedIndex].MonikerString);
				videoSource2.DesiredFrameRate = 20;
				videoSource2.DesiredFrameSize = new Size(640, 480);
				videoSourcePlayer2.VideoSource = videoSource2;
				videoSourcePlayer2.Start();

				timer.Start();
			}
		}

		#region Stop cameras

		/// <summary>
		/// Stopt alle video sources
		/// </summary>
		public void StopCameras()
		{
			timer.Stop();
			StopCamera1();
			StopCamera2();
		}

		/// <summary>
		/// Stopt video source 1
		/// </summary>
		private void StopCamera1()
		{
			videoSourcePlayer1.SignalToStop();
			videoSourcePlayer1.WaitForStop();
			if (frameProcessor1 != null)
				frameProcessor1.reset();
		}

		/// <summary>
		/// Stopt video source 2
		/// </summary>
		private void StopCamera2()
		{
			videoSourcePlayer2.SignalToStop();
			videoSourcePlayer2.WaitForStop();
			if (frameProcessor2 != null)
				frameProcessor2.reset();
		}
		#endregion

		/// <summary>
		/// New frame recieved from video source 1
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="image"></param>
		private void videoSourcePlayer1_NewFrame(object sender, ref Bitmap image)
		{
			frameProcessor1.ProcessFrame(ref image);
		}

		/// <summary>
		/// New frame recieved from video source 2
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="image"></param>
		private void videoSourcePlayer2_NewFrame(object sender, ref Bitmap image)
		{
			frameProcessor2.ProcessFrame(ref image);
		}

		/// <summary>
		/// Open video file 1
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void btnLoadFile1_Click(object sender, EventArgs e)
		{
			if (openFileDialog.ShowDialog() == DialogResult.OK)
			{
				// create video source
				FileVideoSource fileSource = new FileVideoSource(openFileDialog.FileName);

				// open it
				timer.Stop();
				StopCamera1();

				videoSourcePlayer1.VideoSource = fileSource;
				videoSourcePlayer1.Start();

				timer.Start();
			}
		}

		/// <summary>
		/// Open video file 2
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void btnLoadFile2_Click(object sender, EventArgs e)
		{
			if (openFileDialog.ShowDialog() == DialogResult.OK)
			{
				// create video source
				FileVideoSource fileSource = new FileVideoSource(openFileDialog.FileName);

				// open it
				timer.Stop();
				StopCamera2();

				videoSourcePlayer2.VideoSource = fileSource;
				videoSourcePlayer2.Start();

				timer.Start();
			}
		}
	}
}
